package teamproject.graphEditor.graphGenerators;

import java.util.ArrayList;

import teamproject.graphEditor.Controller;
import teamproject.graphEditor.Node;
import teamproject.graphEditor.NodeFactory;
import teamproject.graphEditor.PDEEdge;
import teamproject.graphEditor.PDEEdgeFactory;
import teamproject.graphEditor.SortCollectionsToArray;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DirectedSparseGraph;

/**
 * Generates a cascade network represented by a directed graph.
 */
public class CascadeNetworkGenerator implements GraphGenerator {

	private Controller control;
	private int dimension;
	private DirectedGraph<Node, PDEEdge> g;

	public CascadeNetworkGenerator(Controller control, int dimension) {
		this.control = control;
		this.dimension = dimension;
	}

	private void creatEdges(DirectedGraph<Node, PDEEdge> g) {
		boolean flag = true;
		PDEEdgeFactory factory = control.getEdgeFactory();
		SortCollectionsToArray sca = new SortCollectionsToArray();
		ArrayList<Node> cascadeNodes = sca.sortNodes(g.getVertices());

		g.addEdge(factory.create(), cascadeNodes.get(0), cascadeNodes.get(1));

		for (int i = 2; i < dimension + 2; i++) {
			g.addEdge(factory.create(), cascadeNodes.get(1),
					cascadeNodes.get(i));
		}

		for (int i = 2; i < cascadeNodes.size() - (dimension + 2); i++) {
			if ((i - 2) % dimension == 0) {
				g.addEdge(factory.create(), cascadeNodes.get(i),
						cascadeNodes.get(i + dimension));
				g.addEdge(factory.create(), cascadeNodes.get(i),
						cascadeNodes.get(i + dimension + 1));
				g.addEdge(factory.create(), cascadeNodes.get(i),
						cascadeNodes.get(i + dimension * 2 - 1));

				flag = false;
			}
			if ((i - 2) % dimension == dimension - 1) {
				g.addEdge(factory.create(), cascadeNodes.get(i),
						cascadeNodes.get(i + 1));
				g.addEdge(factory.create(), cascadeNodes.get(i),
						cascadeNodes.get(i + dimension - 1));
				g.addEdge(factory.create(), cascadeNodes.get(i),
						cascadeNodes.get(i + dimension));

				flag = false;
			}
			if (flag) {
				g.addEdge(factory.create(), cascadeNodes.get(i),
						cascadeNodes.get(i + dimension - 1));
				if (i < cascadeNodes.size() - dimension - 2) {
					g.addEdge(factory.create(), cascadeNodes.get(i),
							cascadeNodes.get(i + dimension));
				}
				if (i < cascadeNodes.size() - dimension - 3) {
					g.addEdge(factory.create(), cascadeNodes.get(i),
							cascadeNodes.get(i + dimension + 1));
				}
			}
			flag = true;
		}

		for (int i = cascadeNodes.size() - 2 - dimension; i < cascadeNodes
				.size() - 2; i++) {
			g.addEdge(factory.create(), cascadeNodes.get(i),
					cascadeNodes.get(cascadeNodes.size() - 2));
		}

		g.addEdge(factory.create(), cascadeNodes.get(cascadeNodes.size() - 2),
				cascadeNodes.get(cascadeNodes.size() - 1));
	}

	private void createNodes(DirectedGraph<Node, PDEEdge> g) {
		NodeFactory factory = control.getNodeFactory();

		for (int y = 0; y < dimension; y++) {
			for (int x = 0; x < 3; x++) {
				g.addVertex(factory.create());
			}
		}

		for (int i = 0; i < 4; i++) {
			g.addVertex(factory.create());
		}
		// dimension works now edges
	}

	@Override
	public DirectedGraph<Node, PDEEdge> generateGraph() {

		g = new DirectedSparseGraph<Node, PDEEdge>();
		g = (DirectedGraph<Node, PDEEdge>) control.initNewGraph(g);

		createNodes(g);
		creatEdges(g);

		return g;
	}
}